package com.michaelbulava.TFS.vcs.internal.environments;

import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeList;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.FunctionUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.PairConsumer;
import com.michaelbulava.TFS.vcs.TFSVcs;
import com.michaelbulava.TFS.vcs.exceptions.TFSException;
import com.michaelbulava.TFS.vcs.internal.SharedOperations;
import com.michaelbulava.TFS.vcs.internal.WorkstationHelper;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.core.pendingcheckin.CheckinEvaluationOptions;
import org.jetbrains.annotations.Nullable;

import java.util.*;

/**
 * Created by MichaelA on 8/7/2015.
 */
public class TFSCheckinEnvironment implements CheckinEnvironment {
    private final TFSVcs myVcs;

    public TFSCheckinEnvironment(TFSVcs vcs){
        this.myVcs = vcs;
    }

    @Nullable
    @Override
    public RefreshableOnComponent createAdditionalOptionsPanel(CheckinProjectPanel checkinProjectPanel, PairConsumer<Object, Object> pairConsumer) {
        return null;
    }

    @Nullable
    @Override
    public String getDefaultMessageFor(FilePath[] filePaths) {
        return null;
    }

    @Nullable
    @Override
    public String getHelpId() {
        return null;
    }

    @Override
    public String getCheckinOperationName() {
        return "Checkin";
    }

    @Nullable
    @Override
    public List<VcsException> commit(List<Change> changes, String checkinComment) {
        return commit(changes, checkinComment, FunctionUtil.nullConstant(), null);
    }

    @Nullable
    @Override
    public List<VcsException> commit(List<Change> changes, final String checkinComment,
                                     NullableFunction<Object, Object> nullableFunction,
                                     Set<String> set) {
        List<FilePath> checkinFiles = new ArrayList<>();
        for(Change change : changes){
            FilePath file = null;
            ContentRevision before = change.getBeforeRevision();
            ContentRevision after = change.getAfterRevision();
            if (after != null)
                file = after.getFile();
            else if (before != null)
                file = before.getFile();

            if (file != null)
                checkinFiles.add(file);
        }
        //TODO we need to pull a list of WorkItem assocications, checkin Notes, and/or PolicyOverride info for each
        // workspace here so they can be processed with each workspace's checkin.
        final List<VcsException> errors = new ArrayList<>();
        try {
            WorkstationHelper.processByWorkspaces(checkinFiles, false, myVcs.getProject(),
                    new WorkstationHelper.VoidDelegateProcess() {
                        @Override
                        public void executeRequest(Workspace workspace, List<FilePath> files) throws TFSException {
                            //TODO come back to this to add checkin note and workitem associations...
                            errors.addAll(SharedOperations.performCheckin(myVcs.getProject(), workspace, files, checkinComment,
                                    (CheckinNote) null, (WorkItemCheckinInfo[]) null, (PolicyOverrideInfo) null));

                        }
                    });
        } catch (TFSException e) {
            errors.add(new VcsException(e));
        }
        //TODO clear any stored data with Checkin Notes blah blah blah

        myVcs.fireRevisionChanged();
        return errors;
    }

    @Nullable
    @Override
    public List<VcsException> scheduleMissingFileForDeletion(List<FilePath> list) {
        final List<VcsException> errors = new ArrayList<>();
        try {
            WorkstationHelper.processByWorkspaces(list, false, myVcs.getProject(),
                    new WorkstationHelper.VoidDelegateProcess() {
                        @Override
                        public void executeRequest(Workspace workspace, List<FilePath> localPaths) throws TFSException {
                            Collection<VcsException> schedulingErrors = SharedOperations.scheduleForDeletion(
                                      myVcs.getProject(), workspace, localPaths, null);
                            errors.addAll(schedulingErrors);
                        }
                    });
        } catch (TFSException e) {
            errors.add(new VcsException(e));
        }
        return errors;
    }

    @Nullable
    @Override
    public List<VcsException> scheduleUnversionedFilesForAddition(List<VirtualFile> list) {
        final List<VcsException> errors = new ArrayList<>();
        List<FilePath> addedFile = TFSFileUtil.getFilePaths(list);
        try {
            WorkstationHelper.processByWorkspaces(addedFile, false, myVcs.getProject(),
                    new WorkstationHelper.VoidDelegateProcess() {
                        @Override
                        public void executeRequest(Workspace workspace, List<FilePath> localPaths) throws TFSException {
                            Collection<VcsException> addingErrors = SharedOperations.scheduleForAddition(myVcs.getProject(),
                                    workspace, localPaths);
                            errors.addAll(addingErrors);
                        }
                    });
        } catch (TFSException e) {
            errors.add(new VcsException(e));
        }
        return errors;
    }

    @Override
    public boolean keepChangeListAfterCommit(ChangeList changeList) {
        return false;
    }

    @Override
    public boolean isRefreshAfterCommitNeeded() {
        return true;
    }
}
